//
//  MKUIFillingLayoutConstraint.m
//  MKUI
//
//  Created by sushangjin on 16/6/23.
//  Copyright © 2016年 sushangjin. All rights reserved.
//

#import "MKUIFillingLayoutConstraint.h"
#import "MKUIFlowLayoutConstraint.h"
@interface MKUIFillingLayoutConstraint (){
	BOOL __needConfigSubFlowLayouts;
}
@property(nonatomic,strong) MKUIFlowLayoutConstraint *beforeItemsFlowlayout;
@property(nonatomic,strong) MKUIFlowLayoutConstraint *afterItemsFlowlayout;
@end

@implementation MKUIFillingLayoutConstraint

- (id)copyWithZone:(NSZone *)zone{
    MKUIFillingLayoutConstraint *obj = [super copyWithZone:zone];
    obj.layoutDirection = self.layoutDirection;
    obj.layoutVerticalAlignment = self.layoutVerticalAlignment;
    obj.layoutHorizontalAlignment = self.layoutHorizontalAlignment;
    obj.contentInsets = self.contentInsets;
    obj.interitemSpacing = self.interitemSpacing;
    obj.fillingItem = self.fillingItem;
    return obj;
}
- (id)init{
	if (self=[super init]) {
		self.beforeItemsFlowlayout = [[MKUIFlowLayoutConstraint alloc] init];
		self.afterItemsFlowlayout = [[MKUIFlowLayoutConstraint alloc] init];
		_layoutDirection = MKUILayoutConstraintDirectionHorizontal;
		_layoutVerticalAlignment = MKUILayoutConstraintVerticalAlignmentCenter;
		__needConfigSubFlowLayouts = YES;
	}
	return self;
}
- (void)setFillingItem:(id<MKUILayoutConstraintItemProtocol>)fillingItem{
	_fillingItem = fillingItem;
	__needConfigSubFlowLayouts = YES;
}
- (void)setLayoutDirection:(MKUILayoutConstraintDirection)layoutDirection{
	_layoutDirection = layoutDirection;
	__needConfigSubFlowLayouts = YES;
}
- (void)setLayoutHorizontalAlignment:(MKUILayoutConstraintHorizontalAlignment)layoutHorizontalAlignment{
	_layoutHorizontalAlignment = layoutHorizontalAlignment;
	__needConfigSubFlowLayouts = YES;
}
- (void)setLayoutVerticalAlignment:(MKUILayoutConstraintVerticalAlignment)layoutVerticalAlignment{
	_layoutVerticalAlignment = layoutVerticalAlignment;
	__needConfigSubFlowLayouts = YES;
}
- (void)setItems:(NSArray *)items{
	[super setItems:items];
	__needConfigSubFlowLayouts = YES;
}
- (void)setInteritemSpacing:(CGFloat)interitemSpacing{
	_interitemSpacing = interitemSpacing;
	__needConfigSubFlowLayouts = YES;
}
- (void)setContentInsets:(UIEdgeInsets)contentInsets{
	_contentInsets = contentInsets;
	__needConfigSubFlowLayouts = YES;
}
- (void)__configSubFlowLayouts{
	__needConfigSubFlowLayouts = NO;
	NSArray *items = self.layoutedItems;
	NSInteger fillingItemIndex = [items indexOfObject:self.fillingItem];
    if(fillingItemIndex!=NSNotFound){
        self.beforeItemsFlowlayout.items = fillingItemIndex!=NSNotFound&&fillingItemIndex>0?[items subarrayWithRange:NSMakeRange(0, fillingItemIndex)]:nil;
        self.afterItemsFlowlayout.items = fillingItemIndex!=NSNotFound&&fillingItemIndex<items.count-1?[items subarrayWithRange:NSMakeRange(fillingItemIndex+1, items.count-fillingItemIndex-1)]:nil;
    }else{
        self.beforeItemsFlowlayout.items = items;
        self.afterItemsFlowlayout.items = @[];
    }
	//
	self.beforeItemsFlowlayout.interitemSpacing = self.interitemSpacing;
	self.afterItemsFlowlayout.interitemSpacing = self.interitemSpacing;
	//
	self.beforeItemsFlowlayout.layoutDirection = self.layoutDirection;
	self.afterItemsFlowlayout.layoutDirection = self.layoutDirection;
	//
	if(self.layoutDirection==MKUILayoutConstraintDirectionHorizontal){//水平方向布局,A B C
		self.beforeItemsFlowlayout.layoutVerticalAlignment = self.layoutVerticalAlignment;
		self.afterItemsFlowlayout.layoutVerticalAlignment = self.layoutVerticalAlignment;
		self.beforeItemsFlowlayout.layoutHorizontalAlignment = MKUILayoutConstraintHorizontalAlignmentLeft;
		self.afterItemsFlowlayout.layoutHorizontalAlignment = MKUILayoutConstraintHorizontalAlignmentRight;
	}else{//垂直方向布局
		/**
		 A
		 B
		 C
		 */
		self.beforeItemsFlowlayout.layoutHorizontalAlignment = self.layoutHorizontalAlignment;
		self.afterItemsFlowlayout.layoutHorizontalAlignment = self.layoutHorizontalAlignment;
		self.beforeItemsFlowlayout.layoutVerticalAlignment = MKUILayoutConstraintVerticalAlignmentTop;
		self.afterItemsFlowlayout.layoutVerticalAlignment = MKUILayoutConstraintVerticalAlignmentBottom;
	}
}
- (CGSize)sizeThatFits:(CGSize)size resizeItems:(BOOL)resizeItems{
//	if(__needConfigSubFlowLayouts){
		[self __configSubFlowLayouts];
//	}
	CGSize sizeFits = CGSizeZero;
	UIEdgeInsets insets = self.contentInsets;
	CGRect bounds = CGRectZero;
	bounds.size = size;
	bounds = UIEdgeInsetsInsetRect(bounds, insets);
	CGFloat space = self.interitemSpacing;
	CGRect f1 = bounds;
	CGRect f2 = bounds;
	CGRect f_filling = bounds;
	
	MKCGAxis axis = self.layoutDirection==MKUILayoutConstraintDirectionHorizontal?MKCGAxisX:MKCGAxisY;
	MKCGAxis axisR = MKCGAxisReverse(axis);
	
	CGFloat maxLengthR = 0;
	//计算前半部分
	if(self.fillingItem){
		MKCGRectSetLength(&f1, axis, MKCGRectGetLength(f1, axis)-space);
	}
	CGSize f1_size_fit = [self.beforeItemsFlowlayout sizeThatFits:f1.size resizeItems:resizeItems];
	
	maxLengthR = MAX(maxLengthR,MKCGSizeGetLength(f1_size_fit, axisR));
	//计算后半部分
	if(self.fillingItem){
		MKCGRectSetLength(&f2, axis, MKCGRectGetLength(f2, axis)-space);
	}
	if(MKCGSizeGetLength(f1_size_fit, axis)>0){
		MKCGRectSetLength(&f2, axis, MKCGRectGetLength(f2, axis)-(MKCGSizeGetLength(f1_size_fit, axis)+space));
		MKCGRectSetLength(&f_filling, axis, MKCGRectGetLength(f_filling, axis)-(MKCGSizeGetLength(f1_size_fit, axis)+space));
	}
	CGSize f2_size_fit = [self.afterItemsFlowlayout sizeThatFits:f2.size resizeItems:resizeItems];
	maxLengthR = MAX(maxLengthR,MKCGSizeGetLength(f2_size_fit, axisR));
	//布局填充元素
	if(MKCGSizeGetLength(f2_size_fit, axis)>0){
		MKCGRectSetLength(&f_filling, axis, MKCGRectGetLength(f_filling, axis)-(MKCGSizeGetLength(f2_size_fit, axis)+space));
	}
	CGSize f_filling_size_fit;
	if([self.fillingItem respondsToSelector:@selector(sizeThatFits:resizeItems:)]){
		f_filling_size_fit = [self.fillingItem sizeThatFits:f_filling.size resizeItems:resizeItems];
	}else{
		f_filling_size_fit = [self.fillingItem sizeThatFits:f_filling.size];
	}
	maxLengthR = MAX(maxLengthR,MKCGSizeGetLength(f_filling_size_fit, axisR));
	if(maxLengthR){
		MKCGSizeSetLength(&sizeFits, axisR, maxLengthR+MKUIEdgeInsetsGetEdge(insets, axisR, MKUIEdgeInsetsMin)+MKUIEdgeInsetsGetEdge(insets, axisR, MKUIEdgeInsetsMax));
	}
	MKCGSizeSetLength(&sizeFits, axis, MKCGSizeGetLength(size, axis));
	
	return sizeFits;
}
- (void)layoutItems{
//	if(__needConfigSubFlowLayouts){
		[self __configSubFlowLayouts];
//	}
	[self layoutItemsWithResizeItems:NO];
}
- (void)layoutItemsWithResizeItems:(BOOL)resizeItems{
//	if(__needConfigSubFlowLayouts){
		[self __configSubFlowLayouts];
//	}
	UIEdgeInsets insets = self.contentInsets;
	CGRect bounds = UIEdgeInsetsInsetRect(self.bounds, insets);
	CGFloat space = self.interitemSpacing;
	CGRect f1 = bounds;
	CGRect f2 = bounds;
	CGRect f_filling = bounds;
	
	MKCGAxis axis = self.layoutDirection==MKUILayoutConstraintDirectionHorizontal?MKCGAxisX:MKCGAxisY;
	MKCGAxis axisR = MKCGAxisReverse(axis);
	
	MKCGRectAlignment align = self.layoutDirection==MKUILayoutConstraintDirectionHorizontal? MKCGRectAlignmentFromMKUILayoutConstraintVerticalAlignment(self.layoutVerticalAlignment):MKCGRectAlignmentFromMKUILayoutConstraintHorizontalAlignment(self.layoutHorizontalAlignment);
	
	self.beforeItemsFlowlayout.bounds = f1;
	[self.beforeItemsFlowlayout layoutItemsWithResizeItems:resizeItems];
	//
	id<MKUILayoutConstraintItemProtocol> item1 = [self.beforeItemsFlowlayout.layoutedItems lastObject];
	CGRect item1Frame = [item1 layoutFrame];
	if(item1&&MKCGRectGetMax(item1Frame,axis)!=MKCGRectGetMin(f1, axis)){
		MKCGRectSetMin(&f_filling, axis, MKCGRectGetMax(item1Frame,axis)+space);
		MKCGRectSetLength(&f_filling, axis, MKCGRectGetMax(bounds,axis)-MKCGRectGetMin(f_filling, axis));
		MKCGRectSetMin(&f2, axis, MKCGRectGetMin(f_filling, axis));
		MKCGRectSetLength(&f2, axis, MKCGRectGetLength(f_filling, axis));
	}
	self.afterItemsFlowlayout.bounds = f2;
	[self.afterItemsFlowlayout layoutItemsWithResizeItems:resizeItems];
	id<MKUILayoutConstraintItemProtocol> item2 = [self.afterItemsFlowlayout.layoutedItems firstObject];
	CGRect item2Frame = [item2 layoutFrame];
	if(item2&&MKCGRectGetMin(item2Frame, axis)!=MKCGRectGetMax(f2,axis)){
		MKCGRectSetLength(&f_filling, axis, MKCGRectGetMin(item2Frame, axis)-space-MKCGRectGetMin(f_filling, axis));
	}
	if(resizeItems){
		if([self.fillingItem respondsToSelector:@selector(sizeThatFits:resizeItems:)]){
			CGSize f_filling_size = [self.fillingItem sizeThatFits:f_filling.size resizeItems:resizeItems];
			MKCGRectSetLength(&f_filling, axisR, MKCGSizeGetLength(f_filling_size, axisR));
		}else if([self.fillingItem respondsToSelector:@selector(sizeThatFits:)]){
			CGSize f_filling_size = [self.fillingItem sizeThatFits:f_filling.size];
			MKCGRectSetLength(&f_filling, axisR, MKCGSizeGetLength(f_filling_size, axisR));
		}
	}
	MKCGRectAlignToRect(&f_filling, axisR, align, bounds);
	if([self.fillingItem respondsToSelector:@selector(layoutItemsWithResizeItems:)]){
		[self.fillingItem setLayoutFrame:f_filling];
		[self.fillingItem layoutItemsWithResizeItems:resizeItems];
	}else{
		[self.fillingItem setLayoutFrame:f_filling];
	}
}
@end
MKDEF_EnumTypeCategories(MKUIFillingLayoutConstraintParam,
(@{
   @(MKUIFillingLayoutConstraint_H_C):@"H_C",
   @(MKUIFillingLayoutConstraint_H_T):@"H_T",
   @(MKUIFillingLayoutConstraint_H_B):@"H_B",
   @(MKUIFillingLayoutConstraint_V_C):@"V_C",
   @(MKUIFillingLayoutConstraint_V_L):@"V_L",
   @(MKUIFillingLayoutConstraint_V_R):@"V_R",
   }))
@implementation MKUIFillingLayoutConstraint (InitMethod)
//////////////////////////////////////////////////////////////////////////////
+ (NSDictionary<NSNumber *,NSArray<NSNumber *> *> *)ConstraintParamMapOfHorizontal{
	static NSDictionary<NSNumber *,NSArray<NSNumber *> *> * __share__;
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		NSMutableDictionary<NSNumber *,NSArray<NSNumber *> *> *map = [[NSMutableDictionary alloc] init];
		map[@(MKUIFillingLayoutConstraint_H_C)] = @[
		  @(MKUILayoutConstraintDirectionHorizontal),
		  @(MKUILayoutConstraintVerticalAlignmentCenter),
		  ];
		map[@(MKUIFillingLayoutConstraint_H_T)] = @[
		  @(MKUILayoutConstraintDirectionHorizontal),
		  @(MKUILayoutConstraintVerticalAlignmentTop),
		  ];
		map[@(MKUIFillingLayoutConstraint_H_B)] = @[
		  @(MKUILayoutConstraintDirectionHorizontal),
		  @(MKUILayoutConstraintVerticalAlignmentBottom),
		  ];
		__share__ = map;
	});
	return __share__;
}
+ (NSDictionary<NSNumber *,NSArray<NSNumber *> *> *)ConstraintParamMapOfVertical{
	static NSDictionary<NSNumber *,NSArray<NSNumber *> *> * __share__;
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		NSMutableDictionary<NSNumber *,NSArray<NSNumber *> *> *map = [[NSMutableDictionary alloc] init];
		map[@(MKUIFillingLayoutConstraint_V_C)] = @[
		  @(MKUILayoutConstraintDirectionVertical),
		  @(MKUILayoutConstraintHorizontalAlignmentCenter),
		  ];
		map[@(MKUIFillingLayoutConstraint_V_L)] = @[
		  @(MKUILayoutConstraintDirectionVertical),
		  @(MKUILayoutConstraintHorizontalAlignmentLeft),
		  ];
		map[@(MKUIFillingLayoutConstraint_V_R)] = @[
		  @(MKUILayoutConstraintDirectionVertical),
		  @(MKUILayoutConstraintHorizontalAlignmentRight),
		  ];
		__share__ = map;
	});
	return __share__;
}
+ (NSDictionary<NSArray<NSNumber *> *,NSNumber *> *)ConstraintParamRevertMapOfHorizontal{
	static NSDictionary<NSArray<NSNumber *> *,NSNumber *> * __share__;
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		NSDictionary<NSNumber *,NSArray<NSNumber *> *> *ConstraintParamMap = [self ConstraintParamMapOfHorizontal];
		NSMutableDictionary<NSArray<NSNumber *> *,NSNumber *> *map = [[NSMutableDictionary alloc] initWithCapacity:ConstraintParamMap.count];
		for (NSNumber *key in ConstraintParamMap) {
			map[ConstraintParamMap[key]] = key;
		}
		__share__ = map;
	});
	return __share__;
}
+ (NSDictionary<NSArray<NSNumber *> *,NSNumber *> *)ConstraintParamRevertMapOfVertical{
	static NSDictionary<NSArray<NSNumber *> *,NSNumber *> * __share__;
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		NSDictionary<NSNumber *,NSArray<NSNumber *> *> *ConstraintParamMap = [self ConstraintParamMapOfVertical];
		NSMutableDictionary<NSArray<NSNumber *> *,NSNumber *> *map = [[NSMutableDictionary alloc] initWithCapacity:ConstraintParamMap.count];
		for (NSNumber *key in ConstraintParamMap) {
			map[ConstraintParamMap[key]] = key;
		}
		__share__ = map;
	});
	return __share__;
}
+ (void)parseConstraintParam:(MKUIFillingLayoutConstraintParam)param layoutDirection:(MKUILayoutConstraintDirection *)layoutDirection layoutVerticalAlignment:(MKUILayoutConstraintVerticalAlignment *)layoutVerticalAlignment layoutHorizontalAlignment:(MKUILayoutConstraintHorizontalAlignment *)layoutHorizontalAlignment{
	NSDictionary<NSNumber *,NSArray<NSNumber *> *> *ConstraintParamMapOfHorizontal = [self.class ConstraintParamMapOfHorizontal];
	NSDictionary<NSNumber *,NSArray<NSNumber *> *> *ConstraintParamMapOfVertical = [self.class ConstraintParamMapOfVertical];
	NSArray<NSNumber *> *enums = ConstraintParamMapOfHorizontal[@(param)];
	if(enums){
		*layoutDirection = [enums[0] integerValue];
		*layoutVerticalAlignment = [enums[1] integerValue];
	}else{
		enums = ConstraintParamMapOfVertical[@(param)];
		*layoutDirection = [enums[0] integerValue];
		*layoutHorizontalAlignment = [enums[1] integerValue];
	}
}
+ (MKUIFillingLayoutConstraintParam)constraintParamWithLayoutDirection:(MKUILayoutConstraintDirection)layoutDirection layoutVerticalAlignment:(MKUILayoutConstraintVerticalAlignment)layoutVerticalAlignment layoutHorizontalAlignment:(MKUILayoutConstraintHorizontalAlignment)layoutHorizontalAlignment{
	MKUIFillingLayoutConstraintParam param;
	if(layoutDirection==MKUILayoutConstraintDirectionHorizontal){
		NSDictionary<NSArray<NSNumber *> *,NSNumber *> *ConstraintParamRevertMapOfHorizontal = [self.class ConstraintParamRevertMapOfHorizontal];
		param = (MKUIFillingLayoutConstraintParam)[ConstraintParamRevertMapOfHorizontal[@[@(layoutDirection),@(layoutVerticalAlignment)]] integerValue];
	}else{
		NSDictionary<NSArray<NSNumber *> *,NSNumber *> *ConstraintParamRevertMapOfVertical = [self.class ConstraintParamRevertMapOfVertical];
		param = (MKUIFillingLayoutConstraintParam)[ConstraintParamRevertMapOfVertical[@[@(layoutDirection),@(layoutHorizontalAlignment)]] integerValue];
	}
	return param;
}
//////////////////////////////////////////////////////////////////////////////
- (id)initWithItems:(NSArray<id<MKUILayoutConstraintItemProtocol>> *)items fillingItem:(id<MKUILayoutConstraintItemProtocol>)fillingItem constraintParam:(MKUIFillingLayoutConstraintParam)param contentInsets:(UIEdgeInsets)contentInsets interitemSpacing:(CGFloat)interitemSpacing{
	if(self=[self init]){
		self.items = items;
		self.fillingItem = fillingItem;
		[self configWithConstraintParam:param];
		self.contentInsets = contentInsets;
		self.interitemSpacing = interitemSpacing;
	}
	return self;
}
- (MKUIFillingLayoutConstraintParam)constraintParam{
	MKUIFillingLayoutConstraintParam param = [self.class constraintParamWithLayoutDirection:self.layoutDirection layoutVerticalAlignment:self.layoutVerticalAlignment layoutHorizontalAlignment:self.layoutHorizontalAlignment];
	return param;
}
- (void)setConstraintParam:(MKUIFillingLayoutConstraintParam)constraintParam{
	[self configWithConstraintParam:constraintParam];
}
- (void)configWithConstraintParam:(MKUIFillingLayoutConstraintParam)param{
	MKUILayoutConstraintDirection layoutDirection;
	MKUILayoutConstraintVerticalAlignment layoutVerticalAlignment;
	MKUILayoutConstraintHorizontalAlignment layoutHorizontalAlignment;
	[self.class parseConstraintParam:param layoutDirection:&layoutDirection layoutVerticalAlignment:&layoutVerticalAlignment layoutHorizontalAlignment:&layoutHorizontalAlignment];
	self.layoutDirection = layoutDirection;
	self.layoutVerticalAlignment = layoutVerticalAlignment;
	self.layoutHorizontalAlignment = layoutHorizontalAlignment;
}
@end
